package com.bluesky.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bluesky.common.Constants;
import com.bluesky.common.enums.StatusEnum;
import com.bluesky.common.exception.CustomException;
import com.bluesky.common.utils.SecurityUtils;
import com.bluesky.system.common.dto.SysRoleAddDTO;
import com.bluesky.system.common.dto.SysRoleAssignMenuDTO;
import com.bluesky.system.common.dto.SysRoleEditDTO;
import com.bluesky.system.common.dto.SysRoleQueryDTO;
import com.bluesky.system.entity.*;
import com.bluesky.system.mapper.SysRoleMapper;
import com.bluesky.system.service.*;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author Kevin
 * @since 2021-06-10
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    @Resource
    private ISysTenantService sysTenantService;
    @Resource
    private ISysUserRoleService sysUserRoleService;
    @Resource
    private ISysRoleDeptService sysRoleDeptService;
    @Resource
    private ISysRoleMenuService sysRoleMenuService;
    @Resource
    private ISysDeptService sysDeptService;
    @Resource
    private ISysMenuService sysMenuService;

    @Override
    public IPage<SysRole> page(Page reqPage, SysRoleQueryDTO req) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getRoleCode()), SysRole::getRoleCode, req.getRoleCode());
        queryWrapper.like(StrUtil.isNotBlank(req.getRoleName()), SysRole::getRoleName, req.getRoleName());
        if (!SecurityUtils.getTenantCode().equals(Constants.ADMIN_TENANT)) {
            queryWrapper.eq(SysRole::getTenantId, SecurityUtils.getTenantId());
        }
        queryWrapper.orderByAsc(SysRole::getSort);
        IPage<SysRole> page = this.page(reqPage, queryWrapper);
        page.getRecords().forEach(item -> {
            // 设置租户名称
            SysTenant sysTenant = sysTenantService.getById(item.getTenantId());
            item.setTenantName(Objects.isNull(sysTenant) ? null : sysTenant.getTenantName());
        });
        return page;
    }

    @Override
    public List<SysRole> list(SysRoleQueryDTO req) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getRoleCode()), SysRole::getRoleCode, req.getRoleCode());
        queryWrapper.like(StrUtil.isNotBlank(req.getRoleName()), SysRole::getRoleName, req.getRoleName());
        if (!SecurityUtils.getTenantCode().equals(Constants.ADMIN_TENANT)) {
            queryWrapper.eq(SysRole::getTenantId, SecurityUtils.getTenantId());
        }
        queryWrapper.eq(SysRole::getTenantId, SecurityUtils.getTenantId());
        queryWrapper.orderByAsc(SysRole::getSort);
        return this.list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysRoleAddDTO req) {
        if (!this.checkUniqueRoleName(req.getRoleName(), null, req.getTenantId())) {
            throw new CustomException("角色名称已存在");
        }
        if (!this.checkUniqueRoleCode(req.getRoleCode(), null, req.getTenantId())) {
            throw new CustomException("角色编码已存在");
        }
        SysRole entity = BeanUtil.copyProperties(req, SysRole.class);
        this.save(entity);
        // 删除角色和部门关联
        sysRoleDeptService.remove(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, req.getId()));
        // 新增角色和菜单关联
        if (Objects.nonNull(req.getDeptIds())) {
            req.getDeptIds().forEach(item -> {
                SysRoleDept sysRoleDept = new SysRoleDept();
                sysRoleDept.setRoleId(entity.getId());
                sysRoleDept.setDeptId(item);
                sysRoleDeptService.save(sysRoleDept);
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysRoleEditDTO req) {
        if (!this.checkUniqueRoleName(req.getRoleName(), req.getId(), req.getTenantId())) {
            throw new CustomException("角色名称已存在");
        }
        if (!this.checkUniqueRoleCode(req.getRoleCode(), req.getId(), req.getTenantId())) {
            throw new CustomException("角色编码已存在");
        }
        SysRole entity = BeanUtil.copyProperties(req, SysRole.class);
        this.updateById(entity);
        // 删除角色和部门关联
        sysRoleDeptService.remove(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, req.getId()));
        // 新增角色和菜单关联
        if (Objects.nonNull(req.getDeptIds())) {
            req.getDeptIds().forEach(item -> {
                SysRoleDept sysRoleDept = new SysRoleDept();
                sysRoleDept.setRoleId(entity.getId());
                sysRoleDept.setDeptId(item);
                sysRoleDeptService.save(sysRoleDept);
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(String ids) {
        List<String> idList = Arrays.asList(ids.split(","));
        idList.forEach(item -> {
            SysRole sysRole = this.getById(item);
            SysUserRole sysUserRole = sysUserRoleService.getOne(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getRoleId, item).last("LIMIT 1"));
            if (Objects.nonNull(sysUserRole)) {
                throw new CustomException(String.format("角色【%s】存在用户，无法删除", sysRole.getRoleName()));
            }
            SysRoleDept sysRoleDept = sysRoleDeptService.getOne(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, item).last("LIMIT 1"));
            if (Objects.nonNull(sysRoleDept)) {
                throw new CustomException(String.format("角色【%s】已被使用，无法删除", sysRole.getRoleName()));
            }
        });
        this.removeByIds(Arrays.asList(ids.split(",")));
    }

    @Override
    public SysRole view(String id) {
        return this.getById(id);
    }

    @Override
    public List<SysRole> listOptions() {
        return this.list(Wrappers.lambdaQuery(SysRole.class).eq(SysRole::getStatus, StatusEnum.YES.getCode()).orderByAsc(SysRole::getSort));
    }

    @Override
    public void assignMenu(SysRoleAssignMenuDTO req) {
        // 删除角色和菜单关联
        sysRoleMenuService.remove(Wrappers.lambdaQuery(SysRoleMenu.class).eq(SysRoleMenu::getRoleId, req.getRoleId()));
        // 新增角色和菜单关联
        if (Objects.nonNull(req.getMenuIds())) {
            req.getMenuIds().forEach(item -> {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setRoleId(req.getRoleId());
                sysRoleMenu.setMenuId(item);
                sysRoleMenuService.save(sysRoleMenu);
            });
        }
    }

    @Override
    public List<SysMenu> listRoleMenus(String roleId) {
        List<SysRoleMenu> sysRoleMenuList = sysRoleMenuService.list(Wrappers.lambdaQuery(SysRoleMenu.class).eq(SysRoleMenu::getRoleId, roleId));
        return sysRoleMenuList.stream().map(item ->
                sysMenuService.getById(item.getMenuId())
        ).collect(Collectors.toList());
    }

    @Override
    public List<SysDept> listRoleDepts(String roleId) {
        List<SysRoleDept> sysRoleDeptList = sysRoleDeptService.list(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getRoleId, roleId));
        return sysRoleDeptList.stream().map(item ->
                sysDeptService.getById(item.getDeptId())
        ).collect(Collectors.toList());
    }

    @Override
    public List<SysRole> listSysRoleByUserId(Long userId) {
        List<SysUserRole> sysUserRoleList = sysUserRoleService.list(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, userId));
        if (sysUserRoleList.isEmpty()) {
            return Lists.newArrayList();
        }
        List<Long> roleIdList = sysUserRoleList.stream().map(item -> item.getRoleId()).collect(Collectors.toList());
        return this.list(Wrappers.lambdaQuery(SysRole.class).in(SysRole::getId, roleIdList).eq(SysRole::getStatus, StatusEnum.YES.getCode()));
    }

    @Override
    public List<SysRole> selectOptions(Long tenantId) {
        LambdaQueryWrapper<SysRole> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(SysRole::getStatus, StatusEnum.YES.getCode())
                .eq(SysRole::getTenantId, tenantId)
                .orderByAsc(SysRole::getSort);
        return this.list(queryWrapper);
    }

    private Boolean checkUniqueRoleCode(String value, Long id, Long tenantId) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysRole entity = this.getOne(Wrappers.lambdaQuery(SysRole.class)
                .eq(SysRole::getRoleCode, value)
                .eq(SysRole::getTenantId, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

    private Boolean checkUniqueRoleName(String value, Long id, Long tenantId) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysRole entity = this.getOne(Wrappers.lambdaQuery(SysRole.class)
                .eq(SysRole::getRoleName, value)
                .eq(SysRole::getTenantId, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

}
